#!/usr/bin/env python3
"""
Redis Key 迁移脚本
将旧的 Redis key 迁移到新的统一命名规范

使用方法:
python scripts/migrate_redis_keys.py [--dry-run] [--verbose]

参数:
--dry-run: 只显示将要执行的操作，不实际执行
--verbose: 显示详细的迁移过程
"""

import asyncio
import argparse
import sys
import os
from typing import List, Dict, Tuple
from datetime import datetime

# 添加项目根目录到 Python 路径
script_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.dirname(script_dir)
backend_dir = os.path.join(project_root, 'backend')
sys.path.insert(0, backend_dir)

from app.core.redis_client import redis_manager
from app.core.redis_keys import RedisKeys
from app.utils.logger import get_logger

logger = get_logger(__name__)

class RedisKeyMigrator:
    """Redis Key 迁移器"""
    
    def __init__(self, dry_run: bool = False, verbose: bool = False):
        self.dry_run = dry_run
        self.verbose = verbose
        self.migration_rules = self._define_migration_rules()
        
    def _define_migration_rules(self) -> List[Dict]:
        """定义迁移规则"""
        return [
            # Kafka 配置相关
            {
                'old_pattern': 'kafka:config:connection',
                'new_key_func': lambda: RedisKeys.kafka_config_connection(),
                'description': 'Kafka连接配置'
            },
            
            # 监控数据相关
            {
                'old_pattern': 'monitor:performance:history',
                'new_key_func': lambda: RedisKeys.monitor_performance_history(),
                'description': '性能监控历史数据'
            },
            {
                'old_pattern': 'monitor:performance:latest',
                'new_key_func': lambda: RedisKeys.monitor_performance_latest(),
                'description': '最新性能监控数据'
            },
            {
                'old_pattern': 'monitor:system:metrics',
                'new_key_func': lambda: RedisKeys.monitor_system_metrics(),
                'description': '系统指标数据'
            },
            
            # Topic 偏移量数据 (需要动态处理)
            {
                'old_pattern': 'monitor:topic:*:offsets',
                'new_key_func': lambda topic_name: RedisKeys.monitor_topic_offsets(topic_name),
                'description': 'Topic偏移量历史数据',
                'dynamic': True,
                'extract_params': lambda key: [key.split(':')[2]]  # 提取 topic_name
            },
            
            # 消费者组偏移量数据 (需要动态处理)
            {
                'old_pattern': 'monitor:consumer_group:*:topic:*:offsets',
                'new_key_func': lambda group_id, topic_name: RedisKeys.monitor_consumer_group_offsets(group_id, topic_name),
                'description': '消费者组偏移量历史数据',
                'dynamic': True,
                'extract_params': lambda key: [key.split(':')[2], key.split(':')[4]]  # 提取 group_id, topic_name
            }
        ]
    
    async def scan_old_keys(self) -> List[Tuple[str, Dict]]:
        """扫描需要迁移的旧 key"""
        client = await redis_manager.get_client()
        keys_to_migrate = []
        
        for rule in self.migration_rules:
            if rule.get('dynamic', False):
                # 动态模式：使用模式匹配
                pattern = rule['old_pattern'].replace('*', '*')
                old_keys = await client.keys(pattern)
                
                for old_key in old_keys:
                    if isinstance(old_key, bytes):
                        old_key = old_key.decode('utf-8')
                    
                    # 检查是否已经是新格式
                    if RedisKeys.is_system_key(old_key):
                        continue
                    
                    keys_to_migrate.append((old_key, rule))
            else:
                # 静态模式：直接检查
                old_key = rule['old_pattern']
                exists = await client.exists(old_key)
                if exists and not RedisKeys.is_system_key(old_key):
                    keys_to_migrate.append((old_key, rule))
        
        return keys_to_migrate
    
    async def migrate_key(self, old_key: str, rule: Dict) -> bool:
        """迁移单个 key"""
        try:
            client = await redis_manager.get_client()
            
            # 生成新的 key
            if rule.get('dynamic', False):
                params = rule['extract_params'](old_key)
                new_key = rule['new_key_func'](*params)
            else:
                new_key = rule['new_key_func']()
            
            if self.verbose:
                print(f"  迁移: {old_key} -> {new_key}")
            
            if not self.dry_run:
                # 检查新 key 是否已存在
                if await client.exists(new_key):
                    logger.warning(f"新 key 已存在，跳过迁移: {new_key}")
                    return False
                
                # 重命名 key
                result = await client.rename(old_key, new_key)
                if result:
                    logger.info(f"成功迁移 key: {old_key} -> {new_key}")
                    return True
                else:
                    logger.error(f"迁移失败: {old_key} -> {new_key}")
                    return False
            else:
                return True  # dry-run 模式总是返回成功
                
        except Exception as e:
            logger.error(f"迁移 key 时出错 {old_key}: {e}")
            return False
    
    async def run_migration(self) -> Dict:
        """运行迁移"""
        print(f"🔄 开始 Redis Key 迁移 {'(DRY RUN)' if self.dry_run else ''}")
        print(f"⏰ 时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        print()
        
        # 扫描需要迁移的 key
        print("🔍 扫描需要迁移的 key...")
        keys_to_migrate = await self.scan_old_keys()
        
        if not keys_to_migrate:
            print("✅ 没有找到需要迁移的 key")
            return {
                'total': 0,
                'success': 0,
                'failed': 0,
                'skipped': 0
            }
        
        print(f"📋 找到 {len(keys_to_migrate)} 个需要迁移的 key")
        print()
        
        # 按规则分组显示
        rules_summary = {}
        for old_key, rule in keys_to_migrate:
            desc = rule['description']
            if desc not in rules_summary:
                rules_summary[desc] = []
            rules_summary[desc].append(old_key)
        
        for desc, keys in rules_summary.items():
            print(f"📂 {desc}: {len(keys)} 个 key")
            if self.verbose:
                for key in keys[:5]:  # 只显示前5个
                    print(f"    - {key}")
                if len(keys) > 5:
                    print(f"    ... 还有 {len(keys) - 5} 个")
        print()
        
        if self.dry_run:
            print("🔍 DRY RUN 模式 - 以下是将要执行的迁移操作:")
        else:
            print("🚀 开始执行迁移...")
        
        # 执行迁移
        results = {
            'total': len(keys_to_migrate),
            'success': 0,
            'failed': 0,
            'skipped': 0
        }
        
        for i, (old_key, rule) in enumerate(keys_to_migrate, 1):
            print(f"[{i}/{len(keys_to_migrate)}] {rule['description']}")
            
            success = await self.migrate_key(old_key, rule)
            if success:
                results['success'] += 1
            else:
                results['failed'] += 1
        
        print()
        print("📊 迁移结果:")
        print(f"  总计: {results['total']}")
        print(f"  成功: {results['success']}")
        print(f"  失败: {results['failed']}")
        print(f"  跳过: {results['skipped']}")
        
        if self.dry_run:
            print()
            print("💡 要执行实际迁移，请运行: python scripts/migrate_redis_keys.py")
        
        return results
    
    async def verify_migration(self) -> bool:
        """验证迁移结果"""
        print("🔍 验证迁移结果...")
        
        client = await redis_manager.get_client()
        old_keys_remaining = []
        
        # 检查是否还有旧格式的 key
        for rule in self.migration_rules:
            if rule.get('dynamic', False):
                pattern = rule['old_pattern'].replace('*', '*')
                keys = await client.keys(pattern)
                for key in keys:
                    if isinstance(key, bytes):
                        key = key.decode('utf-8')
                    if not RedisKeys.is_system_key(key):
                        old_keys_remaining.append(key)
            else:
                old_key = rule['old_pattern']
                if await client.exists(old_key) and not RedisKeys.is_system_key(old_key):
                    old_keys_remaining.append(old_key)
        
        if old_keys_remaining:
            print(f"⚠️  仍有 {len(old_keys_remaining)} 个旧格式的 key:")
            for key in old_keys_remaining[:10]:
                print(f"    - {key}")
            if len(old_keys_remaining) > 10:
                print(f"    ... 还有 {len(old_keys_remaining) - 10} 个")
            return False
        else:
            print("✅ 所有 key 都已迁移到新格式")
            return True


async def main():
    """主函数"""
    parser = argparse.ArgumentParser(description='Redis Key 迁移脚本')
    parser.add_argument('--dry-run', action='store_true', help='只显示将要执行的操作，不实际执行')
    parser.add_argument('--verbose', '-v', action='store_true', help='显示详细的迁移过程')
    parser.add_argument('--verify', action='store_true', help='验证迁移结果')
    
    args = parser.parse_args()
    
    migrator = RedisKeyMigrator(dry_run=args.dry_run, verbose=args.verbose)
    
    try:
        if args.verify:
            await migrator.verify_migration()
        else:
            results = await migrator.run_migration()
            
            # 如果不是 dry-run 且有成功的迁移，进行验证
            if not args.dry_run and results['success'] > 0:
                print()
                await migrator.verify_migration()
                
    except KeyboardInterrupt:
        print("\n❌ 迁移被用户中断")
        sys.exit(1)
    except Exception as e:
        print(f"\n❌ 迁移过程中出错: {e}")
        logger.error(f"迁移脚本执行失败: {e}")
        sys.exit(1)


if __name__ == '__main__':
    asyncio.run(main())
